#include "adc.h"

#include "fsl_adc.h"
//#include "fsl_adc_etc.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
#include "appCommon.h"

#define PEDAL_ADC_BASE          ADC1
#define PEDAL_ADC_CHANNEL_GROUP 0U

#define PEDAL_ADC_IRQn          ADC1_IRQn
#define PEDAL_ADC_IRQHandler    ADC1_IRQHandler

#define  OUTPUT_HC4051_A_FUN    IOMUXC_GPIO_B0_03_GPIO2_IO03
#define  OUTPUT_HC4051_A_PORT   GPIO2
#define  OUTPUT_HC4051_A_PIN    3

#define  OUTPUT_HC4051_B_FUN    IOMUXC_GPIO_B0_00_GPIO2_IO00
#define  OUTPUT_HC4051_B_PORT   GPIO2
#define  OUTPUT_HC4051_B_PIN    0

#define  OUTPUT_HC4051_C_FUN    IOMUXC_GPIO_SD_B1_02_GPIO3_IO02
#define  OUTPUT_HC4051_C_PORT   GPIO3
#define  OUTPUT_HC4051_C_PIN    2

#define ADC_RESAULT_SIZE        15


static volatile bool g_AdcConversionDoneFlag;
static volatile uint32_t g_AdcConversionValue;
static adc_channel_config_t adcChannelConfigStruct;

// const uint32_t adcChannelNum[MAX_CHANNEL]={8,9,10,11,12};

static uint8_t adcChannelIndex = 0;
static uint8_t g_AdcConversionCount1 = 0;

static uint16_t adcResaultValue0 ;
static uint16_t adcResaultValue1 ;

static uint16_t adcResaultLastValue0 = 0;
static uint16_t adcResaultLastValue1 = 0;

static uint32_t adcResaultBuff[MAX_CHANNEL] ;

static uint32_t adcFilterTimes = 0;
static uint32_t adcValueMin;
static uint32_t adcValueMax;
static uint32_t adcValueAdd;

static uint32_t adcFilterMin[MAX_CHANNEL];
static uint32_t adcFilterMax[MAX_CHANNEL];
static uint32_t adcFilterAdd[MAX_CHANNEL];
static uint32_t adcFilterChannelCount[MAX_CHANNEL];


static void adcSetChannel(uint32_t channel);

void adcInit(void)
{
    adc_config_t adcConfig;

    const  gpio_pin_config_t  gpio_pin_output_config  =  {
            .direction      =  kGPIO_DigitalOutput,
            .outputLogic    =  1U,
            .interruptMode  =  kGPIO_NoIntmode
    };
    IOMUXC_SetPinMux(OUTPUT_HC4051_A_FUN, 0U);
    IOMUXC_SetPinConfig(OUTPUT_HC4051_A_FUN, GPIO_OUTPUT_CONFIG);
    IOMUXC_SetPinMux(OUTPUT_HC4051_B_FUN, 0U);
    IOMUXC_SetPinConfig(OUTPUT_HC4051_B_FUN, GPIO_OUTPUT_CONFIG);
    IOMUXC_SetPinMux(OUTPUT_HC4051_C_FUN, 0U);
    IOMUXC_SetPinConfig(OUTPUT_HC4051_C_FUN, GPIO_OUTPUT_CONFIG);

    GPIO_PinInit(OUTPUT_HC4051_A_PORT, OUTPUT_HC4051_A_PIN, &gpio_pin_output_config);
    GPIO_PinInit(OUTPUT_HC4051_B_PORT, OUTPUT_HC4051_B_PIN, &gpio_pin_output_config);
    GPIO_PinInit(OUTPUT_HC4051_C_PORT, OUTPUT_HC4051_C_PIN, &gpio_pin_output_config);

    // IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_03_GPIO1_IO19,0U);
    // IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_03_GPIO1_IO19,GPIO_ADC_CONFIG);
    // IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_04_GPIO1_IO20,0U);
    // IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_04_GPIO1_IO20,GPIO_ADC_CONFIG);
    // IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_05_GPIO1_IO21,0U);
    // IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_05_GPIO1_IO21,GPIO_ADC_CONFIG);
    // IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22,0U);
    // IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22,GPIO_ADC_CONFIG);
    // IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_07_GPIO1_IO23,0U);
    // IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_07_GPIO1_IO23,GPIO_ADC_CONFIG);
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_GPIO1_IO25,0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_09_GPIO1_IO25,GPIO_ADC_CONFIG);




/*
 *  config->enableAsynchronousClockOutput = true;
 *  config->enableOverWrite =               false;
 *  config->enableContinuousConversion =    false;
 *  config->enableHighSpeed =               false;
 *  config->enableLowPower =                false;
 *  config->enableLongSample =              false;
 *  config->referenceVoltageSource =        kADC_ReferenceVoltageSourceAlt0;
 *  config->samplePeriodMode =              kADC_SamplePeriod2or12Clocks;
 *  config->clockSource =                   kADC_ClockSourceAD;
 *  config->clockDriver =                   kADC_ClockDriver1;
 *  config->resolution =                    kADC_Resolution12Bit;
*/
    /* Initialize the ADC module. */
    ADC_GetDefaultConfig(&adcConfig);

    adcConfig.samplePeriodMode = kADC_SamplePeriod8or24Clocks;
    adcConfig.clockDriver      = kADC_ClockDriver8;
    ADC_Init(PEDAL_ADC_BASE, &adcConfig);
//    ADC_EnableHardwareTrigger(PEDAL_ADC_BASE, true);
#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
    ADC_EnableHardwareTrigger(PEDAL_ADC_BASE, false);
#endif

    /* Do auto hardware calibration. */
    if (kStatus_Success == ADC_DoAutoCalibration(PEDAL_ADC_BASE))
    {

    }
    else
    {

    }
    NVIC_SetPriority(PEDAL_ADC_IRQn, 8);
    EnableIRQ(PEDAL_ADC_IRQn);
    adcChannelIndex = 0 ;
    adcSetChannel(adcChannelIndex + 1);
    // adcChannelConfigStruct.channelNumber = adcChannelNum[adcChannelIndex];
    adcChannelConfigStruct.channelNumber = 14;
    adcChannelConfigStruct.enableInterruptOnConversionCompleted = true;
    //ADC_SetChannelConfig(PEDAL_ADC_BASE, PEDAL_ADC_CHANNEL_GROUP, &adcChannelConfigStruct);
}

void PEDAL_ADC_IRQHandler(void)
{
    uint32_t curAdc ,diff;

	curAdc = ADC_GetChannelConversionValue(PEDAL_ADC_BASE, PEDAL_ADC_CHANNEL_GROUP);
    curAdc = 4095 - curAdc;
	adcValueAdd += curAdc;
	if(curAdc > adcValueMax)
	{
		adcValueMax = curAdc;
	}
	else if(curAdc < adcValueMin)
	{
		adcValueMin = curAdc;
	}
	if(++ adcFilterTimes >= ADC_RESAULT_SIZE)
	{
        curAdc = (adcValueAdd - adcValueMax - adcValueMin) / (ADC_RESAULT_SIZE - 2);
        adcFilterAdd[adcChannelIndex] += curAdc;
        adcFilterMax[adcChannelIndex] = curAdc > adcFilterMax[adcChannelIndex] ? curAdc : adcFilterMax[adcChannelIndex];
        adcFilterMin[adcChannelIndex] = curAdc < adcFilterMin[adcChannelIndex] ? curAdc : adcFilterMin[adcChannelIndex];
        if( ++ adcFilterChannelCount[adcChannelIndex] >= ADC_RESAULT_SIZE )
        {
            curAdc = (adcFilterAdd[adcChannelIndex] - adcFilterMax[adcChannelIndex] - adcFilterMin[adcChannelIndex]) / (ADC_RESAULT_SIZE - 2);
            diff = curAdc > adcResaultBuff[adcChannelIndex] ? (curAdc - adcResaultBuff[adcChannelIndex]) : (adcResaultBuff[adcChannelIndex] - curAdc);
            if(curAdc < 15)
            {
                curAdc = 0 ;
            }
            if((diff >= 5) || (curAdc > 4060))
            {
                adcResaultBuff[adcChannelIndex] = curAdc;
            }
            adcFilterMax[adcChannelIndex] = 0;
            adcFilterMin[adcChannelIndex] = 4096;
            adcFilterChannelCount[adcChannelIndex] = 1 ;
            adcFilterAdd[adcChannelIndex] = curAdc;
        }
		adcChannelIndex = (adcChannelIndex + 1) % MAX_CHANNEL;
		adcFilterTimes = 0 ;
		adcValueAdd = 0;
		adcValueMin = 4096;
		adcValueMax = 0 ;
        adcSetChannel(adcChannelIndex + 1);
        // adcChannelConfigStruct.channelNumber = adcChannelNum[adcChannelIndex];
//        if(adcChannelIndex == 0)
//        {
//            writeADCValue(adcResaultBuff,MAX_CHANNEL);
//        }
//        else
        {
            ADC_SetChannelConfig(PEDAL_ADC_BASE, PEDAL_ADC_CHANNEL_GROUP, &adcChannelConfigStruct);
        }
	}
    else
    {
        ADC_SetChannelConfig(PEDAL_ADC_BASE, PEDAL_ADC_CHANNEL_GROUP, &adcChannelConfigStruct);
    }
    __DSB();
}

uint32_t adcReadValue(uint8_t ch)
{
	return adcResaultBuff[ch];
}

void adcStartConvert(void)
{
    ADC_SetChannelConfig(PEDAL_ADC_BASE, PEDAL_ADC_CHANNEL_GROUP, &adcChannelConfigStruct);
}

static void adcSetChannel(uint32_t channel)
{
    switch(channel)
    {
        case 0:
        OUTPUT_HC4051_A_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 1:
        OUTPUT_HC4051_A_PORT->DR_SET    = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 2:
        OUTPUT_HC4051_A_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_SET    = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 3:
        OUTPUT_HC4051_A_PORT->DR_SET    = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_SET    = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 4:
        OUTPUT_HC4051_A_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_SET    = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 5:
        OUTPUT_HC4051_A_PORT->DR_SET    = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_SET    = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 6:
        OUTPUT_HC4051_A_PORT->DR_CLEAR  = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_SET    = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_SET    = 1ul << OUTPUT_HC4051_C_PIN;
        break;
        case 7:
        OUTPUT_HC4051_A_PORT->DR_SET    = 1ul << OUTPUT_HC4051_A_PIN;
        OUTPUT_HC4051_B_PORT->DR_SET    = 1ul << OUTPUT_HC4051_B_PIN;
        OUTPUT_HC4051_C_PORT->DR_SET    = 1ul << OUTPUT_HC4051_C_PIN;
        break;
    }
}
